import unittest

from google.appengine.ext import db
from google.appengine.ext import testbed

##@details Captures the required information about every profiler
class Profiler(db.Model):
    user = db.UserProperty(required=True)
    nickname = db.StringProperty(required=True)
    registered = db.DateTimeProperty(auto_now_add=True)
    modified = db.DateTimeProperty(auto_now_add=True)
    money = db.IntegerProperty(required=True)
    # For refills
    times_busted = db.IntegerProperty(default=0)
    excuse = db.StringProperty()
    
    # Track the popularity of the games
    hands_per_level = db.ListProperty(int, "Number of hands played", [0] * 4)
    challenges = db.ListProperty(int, "Number of challenges completed", [0] * 2)

    def print_column_names(self):
        cols = []
        for (key, _) in self.__dict__.iteritems():
            if not key in db.Model().__dict__:
                if key:
                    col_name = str(key)[1:].replace("_", " ").upper()
                    cols.append(col_name)
                else:
                    cols.append("")
        return "</th><th>".join(cols)
    
    def print_row(self):
        cols = []
        for (key, value) in self.__dict__.iteritems():
            if not key in db.Model().__dict__:
                if value:
                    cols.append(str(value))
                else:
                    cols.append("")
        return "</td><td>".join(cols)
    
##@details Captures the current information about the game
## Currently used by level 5
class Game(db.Model):
    # These are set once for every new game
    user = db.UserProperty(required=True)
    bet_amount = db.IntegerProperty(default=0)
    started = db.DateTimeProperty(auto_now_add=True)
    my_cards = db.StringListProperty()
    table_cards = db.StringListProperty()
    your_cards = db.StringListProperty()
    challenge_level = db.IntegerProperty(default=0)
    
    # These are modified every round
    hand_number = db.IntegerProperty(default=0)
    i_deal = db.BooleanProperty(default=False)
    big_blind = db.IntegerProperty(default=2)
    round = db.IntegerProperty(default=0)
    round_over = db.BooleanProperty(default=False)
    preflop_bids = db.ListProperty(int,default=[])
    flop_bids = db.ListProperty(int, default=[])
    turn_bids = db.ListProperty(int, default=[])
    river_bids = db.ListProperty(int, default=[])
    message = db.StringProperty()
    # Balance is how much the computer needs to add to equalize
    balance = db.IntegerProperty(default=0)
    modified = db.DateTimeProperty(auto_now_add=True)
    my_money = db.IntegerProperty(default=0)
    your_money = db.IntegerProperty(default=0)
    pot_money = db.IntegerProperty(default=0)
    all_in = db.BooleanProperty(default=False)
    
    # For debugging
    debug = db.StringProperty()

    def print_status(self):
        ret = "The balance is %d.  The pot is %d" % (
                self.balance, self.pot_money)
        
        # For debugging more
        ret += ". The round is %d, the hand number is %d" % (self.round, self.hand_number)
        return ret
    
    def print_preflop_bidding(self):
        return self.print_bidding(0)
    
    def print_flop_bidding(self):
        return self.print_bidding(1)

    def print_turn_bidding(self):
        return self.print_bidding(2)
    
    def print_river_bidding(self):
        return self.print_bidding(3)

    def print_bidding(self, round=0):
        if round == 0:
            return "The preflop bidding is %s" % self.preflop_bids
        elif round == 1:
            return "The flop bidding is %s" % self.flop_bids
        elif round == 2:
            return "The turn bidding is %s" % self.turn_bids
        elif round == 3:
            return "The river bidding is %s" % self.river_bids
        else:
            return "I don't know what you want me to print!"

    def print_preflop_bids(self):
        ret = ""
        start_index = 2
        balance = self.bids[2] - self.bids[1]
        blinds_str = ". %s PUT %d. %s PUT %d"
        if self.i_deal:
            ret += blinds_str % ("I", self.bids[1], "YOU", self.bids[2])
        else:
            ret += blinds_str % ("YOU", self.bids[1], "I", self.bids[2])
        
        if not self.i_deal:
            odd_person = "I"
            even_person = "YOU"
        else:
            odd_person = "YOU"
            even_person = "I"
        
        for i in xrange(len(self.bids) - start_index):
            j = i + start_index
            if j % 2 == 1:
                bid_str = ". " + odd_person
            else:
                bid_str = ". " + even_person
            
            if self.bids[j] < -1:
                print "A bid less than -1? No way"
                raise
            if self.bids[j] == -1:
                action_str = " FOLDED"
            elif self.bids[j] == 0:
                action_str = " CHECKED"
            else:
                balance -= self.bids[j]
                if balance > 0:
                    print "We didn't fully call? What?"
                    raise
                elif balance == 0:
                    action_str = " CALLED %d" % self.bids[j]
                else:
                    balance *= -1
                    if balance == self.bids[j]:
                        action_str = " BID %d" % self.bids[j]
                    else:
                        action_str = " CALLED %d and RAISED %d" % (
                                self.bids[j] - balance, balance) 
            ret += bid_str + action_str
        ret += "." 
        return ret
    
    def print_round_N_bids(self, round):
        start_index = 0
        balance = 0
        ret = ""
        if (self.round == 0 and not self.i_deal) or self.i_deal:
            odd_person = "I"
            even_person = "YOU"
        else:
            odd_person = "YOU"
            even_person = "I"
        
        for i in xrange(len(self.bids) - start_index):
            j = i + start_index
            if j % 2 == 1:
                bid_str = ". " + odd_person
            else:
                bid_str = ". " + even_person
            
            if self.bids[j] < -1:
                print "A bid less than -1? No way"
                raise
            if self.bids[j] == -1:
                action_str = " FOLDED"
            elif self.bids[j] == 0:
                action_str = " CHECKED"
            else:
                balance -= self.bids[j]
                if balance > 0:
                    print "We didn't fully call? What?"
                    raise
                elif balance == 0:
                    action_str = " CALLED %d" % self.bids[j]
                else:
                    balance *= -1
                    if balance == self.bids[j]:
                        action_str = " BID %d" % self.bids[j]
                    else:
                        action_str = " CALLED %d and RAISED %d" % (
                                self.bids[j] - balance, balance) 
            ret += bid_str + action_str
        ret += "." 
        return ret

class PrevHand(db.Model):
    # These are set once for every new game
    user = db.UserProperty(required=True)
    started = db.DateTimeProperty(auto_now_add=True)
    my_images = db.StringListProperty()
    table_images = db.StringListProperty()
    your_images = db.StringListProperty()
    result_message = db.StringProperty()
    modified = db.DateTimeProperty(auto_now_add=True)
    
    # For debugging
    debug = db.StringProperty()

class ProfilerTestCase(unittest.TestCase):
    def setUp(self):
        # First, create an instance of the Testbed class.
        self.testbed = testbed.Testbed()
        # Then activate the testbed, which prepares the service stubs for use.
        self.testbed.activate()
        # Next, declare which service stubs you want to use.
        self.testbed.init_datastore_v3_stub()
    
    def tearDown(self):
        self.testbed.deactivate()
        
    def testInsertEntity(self):
        Profiler().put()
        self.assertEqual(1, len(Profiler.all().fetch(2)))